package jpave.query_interface;

import java.awt.*;
import javax.swing.*;

import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.*;
import java.io.File;

import util.ui.CachedTable;
import util.ui.UserPrompt;
import util.Debug.ErrorReport;
import util.methods.*;
import jpave.dataholders.BasicQueryData;
import jpave.dataholders.MainData;
import jpave.dataholders.FilterContigData;
import jpave.dataholders.QueryData;
import jpave.manager.ManagerFrame;

public class ContigListTab extends Tab
{		
	public ContigListTab (  JPaveFrame inFrame, FieldMapper inContigFields,
							BasicQueryData inQuery, 
							String inCacheFileName,
							int nTotalContigs, boolean isBasicQuery, int viewMode) throws Exception
	{
		super(inFrame, null);

		setBackground(Color.WHITE);
		this.isBasicQuery = isBasicQuery;
		nViewMode = viewMode;
		theBasicQuery = inQuery;
		theQuery = null;
        theFields = inContigFields;
        
		// Table of Contig data
		contigTable = new CachedTable ( 
				theFields, 
				inCacheFileName,
				theFields.getVisibleFieldIDs(),
				refreshListener
		);

		contigTable.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
		contigTable.setOnlySingleRowSelection ( );
		contigTable.getTableHeader().setBackground(Color.WHITE);
		contigTable.addSelectionChangeListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				if ( btnViewContig != null )
					btnViewContig.setEnabled( contigTable.getSelectedRowCount() > 0 );
			}
		});
		contigTable.addDoubleClickListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				addContigTab();
			}
		});
		
		JPanel scrollPane = new JPanel();

		scrollPane.setAlignmentY(LEFT_ALIGNMENT);
		scrollPane.add(contigTable);
		JScrollPane scroller = new JScrollPane ( contigTable );
		scroller.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED );
		scroller.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED );
		scroller.getViewport().setBackground(Color.WHITE);
		UIHelpers.setScrollIncrements( scroller );
		
		JPanel toolBar = createToolbar ( );
		toolBar.setBackground(Color.WHITE);

		lblSummary = new JLabel ("Displaying " + contigTable.getEntryCount() + " of " + nTotalContigs + " sequences");
		lblSummary.setBackground(Color.WHITE);
		
		setLayout( new BoxLayout ( this, BoxLayout.Y_AXIS ) );
		add ( Box.createVerticalStrut(5) );
		add ( lblSummary );
		add ( Box.createVerticalStrut(5) );
		add ( toolBar );
		add ( Box.createVerticalStrut(5) );
		add ( scroller );

		contigTable.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
		contigTable.setOnlySingleRowSelection ( );
	}
	// Show All Contigs and Filer
	public ContigListTab ( 	JPaveFrame inFrame, FieldMapper inContigFields, 
							QueryData inQuery, String [] contigs, 
							String inCacheFileName, 
							int nTotalContigs)
	throws Exception
	{
		super(inFrame, null);

		// Save references to inputs
		theContigIDs = contigs;
		theQuery = inQuery;
		theBasicQuery = null;
        theFields = inContigFields;
        super.setBackground(Color.WHITE);
        
		// Table of Contig data
		contigTable = new CachedTable ( 
				theFields, 
				inCacheFileName,
				theFields.getVisibleFieldIDs(),
				refreshListener
		);

		contigTable.setSelectionMode( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
		contigTable.getTableHeader().setBackground(Color.WHITE);
		contigTable.addSelectionChangeListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				if ( btnViewContig != null )
					btnViewContig.setEnabled( contigTable.getSelectedRowCount() > 0 );
			}
		});
		contigTable.addDoubleClickListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				addContigTab();
			}
		});
		
		JPanel scrollPane = new JPanel();

		scrollPane.setAlignmentY(LEFT_ALIGNMENT);
		scrollPane.add(contigTable);
		JScrollPane scroller = new JScrollPane ( contigTable );
		scroller.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED );
		scroller.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED );
		scroller.getViewport().setBackground(Color.WHITE);
		UIHelpers.setScrollIncrements( scroller );
		
		JPanel toolBar = createToolbar ( );
		toolBar.setBackground(Color.WHITE);

		lblSummary = new JLabel ("Displaying " + contigTable.getEntryCount() + " of " + nTotalContigs + " sequences");
		
		setLayout( new BoxLayout ( this, BoxLayout.Y_AXIS ) );
		add ( Box.createVerticalStrut(5) );
		add ( lblSummary );
		add ( Box.createVerticalStrut(5) );
		add ( toolBar );
		add ( Box.createVerticalStrut(5) );
		add ( scroller );
	}
	
	private ActionListener refreshListener = new ActionListener() {
		public void actionPerformed(ActionEvent event) {
			doRefreshColumns();
		}
	};
	
	public QueryData getQuery ( ) { return theQuery; }
	public String [] getContigIDs() { return theContigIDs; }
	public boolean isFromBasicContigQuery() { return nViewMode == JPaveFrame.BASIC_QUERY_MODE_UNITRANS; }
	public int getViewMode() { return nViewMode; }
	
	public FieldMapper getFieldMapper ( ) { return theFields; }
	
	private JPanel createToolbar ( )
	{
		final JPanel toolbarPanel = new JPanel ( );

		// Setup the Button panel.  (Everything above the table.)	
		btnViewContig = new JButton("View Selected Sequence");
		btnViewContig.setBackground(ManagerFrame.FUNCTIONCOLOR);
		btnViewContig.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				if (contigTable.getSelectedRowCount() == 1)
					addContigTab();
				else // more than one contig selected
					addClusterTab();
			}
		});
		btnViewContig.setEnabled( false );
		
		JButton btnRefresh = new JButton ("Refresh Columns");
		btnRefresh.addActionListener(refreshListener);	
		
		JButton btnCopy = new JButton ("Copy to Query");
		btnCopy.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if(!isBasicQuery)
				{
					QueryTab tab = getParentFrame().getQueryTab();
					tab.setUIFromFilter(theQuery);
				}
			}
		});	
		
		/****************************************************
		 * Dialog box is defines further down in file.
		 * The methods to write to file are defined in SortableTable
		 */
		JButton btnSave = new JButton("Export"); 
		btnSave.setBackground(ManagerFrame.PROMPTCOLOR);
		btnSave.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				final ExportType et = new ExportType();
				et.setVisible(true);
				
				final int saveMode = et.getSelection();
				
				if(saveMode != ExportType.EXPORT_CANCEL) {
					final JFileChooser fc = new JFileChooser(getParentFrame().lastSaveFilePath);
					if(saveMode == ExportType.EXPORT_TABLE) fc.setSelectedFile(new File("TableOfSeqs.csv"));
					else if(saveMode == ExportType.EXPORT_UNITRANS) fc.setSelectedFile(new File("SeqsInTable.fasta"));
					else if(saveMode == ExportType.EXPORT_ORF) fc.setSelectedFile(new File("OrfsInTable.fasta"));
					else if(saveMode == ExportType.EXPORT_GO) fc.setSelectedFile(new File("GOsForTable.csv"));
					else if(saveMode == ExportType.EXPORT_MEV)fc.setSelectedFile(new File("ReadCounts"));
					else if(saveMode == ExportType.EXPORT_R)fc.setSelectedFile(new File("RPKM"));
					else if(saveMode == ExportType.EXPORT_R2)fc.setSelectedFile(new File("RPKMlog"));
					
					if (fc.showSaveDialog(toolbarPanel) == JFileChooser.APPROVE_OPTION) {
						final File f = fc.getSelectedFile();
						int writeOption = JOptionPane.YES_OPTION;
						if (f.exists()) {
							writeOption = JOptionPane.showConfirmDialog(
								    toolbarPanel,
								    "The file already exists, overwrite it?",
								    "Save to File",
								    JOptionPane.YES_NO_OPTION);
						}
						if (writeOption == JOptionPane.YES_OPTION) {
							getParentFrame().setLastPath(f.getPath());
							Thread theThread = new Thread(new Runnable() {
								public void run() {
									try {
										if(saveMode == ExportType.EXPORT_TABLE) {
											contigTable.saveToFileTabDelim(f);
										}
										else if(saveMode == ExportType.EXPORT_UNITRANS) {
                                            contigTable.saveToFasta(f, 
                                               getParentFrame().getAssemblyList().getAllAssembly().createConnection());
                                        }
                                        else if(saveMode == ExportType.EXPORT_ORF) {
                                            contigTable.saveORFToFasta(f, 
                                               getParentFrame().getAssemblyList().getAllAssembly().createConnection());
                                        }
                                        else if(saveMode == ExportType.EXPORT_MEV) {
											contigTable.saveToFileMeV(f, 
											   getParentFrame().getAssemblyList().getAllAssembly().createConnection(),
											   getParentFrame().getQueryTab().getAllLibraryNames(false)); 
										}
										else if(saveMode == ExportType.EXPORT_R) {
											contigTable.saveToFilePCC(f, 
											   et.getPCCString(),
											   getParentFrame().getQueryTab().getAllLibraryNames(false)); // dead boolean
										}
										else if(saveMode == ExportType.EXPORT_R2) {
                                            contigTable.saveToFilePCClog2(f, 
                                            		et.getPCCString(),
                                               getParentFrame().getQueryTab().getAllLibraryNames(false)); // dead boolean
                                        }
										else if(saveMode == ExportType.EXPORT_GO) {
                                            contigTable.saveToFileGO(f, et.getGOLevel(),
                                            		getParentFrame().getAssemblyList().getAllAssembly().createConnection()); 
                                        }

									}
									catch(Exception e) {
										ErrorReport.prtReport(e, "Error creating");
									}
								}
							});
							theThread.start();
						}
					}
				}
			}
		});
		JButton btnCopyTable = new JButton("Copy Table");
		btnCopyTable.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				try {
					Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
					StringSelection stuff = new StringSelection(contigTable.copyTableToString());
					cb.setContents(stuff, null);
				} catch (Exception e) {	
					ErrorReport.reportError(e, "Error copying table");
				} catch (Error e) {
					ErrorReport.reportFatalError(e, "Fatal error copying table", null);
				}
			}
		});
		
		btnHelp = new JButton("Help");
		btnHelp.setBackground(ManagerFrame.HELPCOLOR);
		btnHelp.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				UserPrompt.displayHTMLResourceHelp(getParentFrame(), "Sequence table", "html/viewSingleTCW/ContigListTab.html");
			}
		});

		toolbarPanel.add( Box.createHorizontalStrut(5) );
		toolbarPanel.add( btnViewContig );
		toolbarPanel.add(btnRefresh);
		toolbarPanel.add(btnSave);
		toolbarPanel.add(btnCopyTable);
		toolbarPanel.add( Box.createHorizontalStrut(5) );
		toolbarPanel.add( btnHelp );
		toolbarPanel.setMaximumSize( new Dimension ( Integer.MAX_VALUE, 
				(int)toolbarPanel.getPreferredSize ().getHeight() ) );		
		return toolbarPanel;
	}
	
	private void doRefreshColumns() {
		if(theContigIDs != null)
			getParentFrame().handleLoadQuery( ContigListTab.this, theQuery, theContigIDs, nViewMode,  null );
		else if(theQuery != null)
			getParentFrame().handleLoadQuery( ContigListTab.this, theQuery, null );
		else
			getParentFrame().handleLoadQuery(ContigListTab.this, theBasicQuery, null, null);
	}
	// more than one contig selected
	private void addClusterTab ( )
	{		
		String[] contigNames = getSelectedContigIDs();
		
		MainData theCluster = new MainData ();
		for (int i = 0;  i < contigNames.length;  i++)  {
			theCluster.addContigStub( contigNames[i] );
		}
		
		String strName = contigTable.getSelectedRowCount() + " contigs";
		getParentFrame().addClusterPage(theCluster, strName, this, -1);
	}
	// one contig selected
	private void addContigTab ( )
	{
		int nRow = contigTable.getSelectedRow();
		
		if (nRow < 0)return;
		
		String strName = getSelectedContigID();
		getParentFrame().addContigPage(strName, this, nRow, JPaveFrame.ShowAllContigs);
	}
	
	public String getContigIDAtRow(int nRow) {
		if (nRow >= 0 && nRow < contigTable.getVisibleRowCount())
			return (String)theFields.extractFieldByID( contigTable.getRowAt(nRow), 
					FilterContigData.CONTIG_ID_FIELD );		
		return null;
	}
	
	private String getSelectedContigID ()
	{
		int nRow = contigTable.getSelectedRow();
		if (nRow >= 0 && contigTable.getSelectedRowCount() == 1)
			return (String)theFields.extractFieldByID( contigTable.getRowAt(nRow), 
					FilterContigData.CONTIG_ID_FIELD );		
		return null;
	}
	
	private String[] getSelectedContigIDs ()
	{
		int[] indices = contigTable.getSelectedRows();
		String[] names = new String[indices.length];
		
		int j = 0;
		for (int i = 0;  i < indices.length;  i++) {
			if (indices[i] >= 0 && indices[i] < contigTable.getEntryCount())
				names[j++] = (String)theFields.extractFieldByID( 
						contigTable.getRowAt(indices[i]), FilterContigData.CONTIG_ID_FIELD );
		}		
		return names;
	}
	
	public int getNextRowNum ( int nRow )
	{
		int nNextRow = nRow + 1;
		if (nNextRow >= contigTable.getVisibleRowCount()) 
			nNextRow = 0;
		return nNextRow;
	}
	
	public int getPrevRowNum ( int nRow )
	{
		int nPrevRow = nRow - 1;
		if (nPrevRow < 0)
			nPrevRow = contigTable.getVisibleRowCount() - 1; // get last row
		return nPrevRow;
	}

	/**
	 * Cleanup for cache files and used memory
	 */
	public void close() {
		contigTable.removeCache();
		theFields = null;
		if(theQuery != null) theQuery.clear();
		if(theBasicQuery != null) theBasicQuery.clear();
		btnViewContig = null;
		contigTable = null;
		lblSummary = null;
		
		//Garbage collect
		//Runtime.getRuntime().gc();
	}

	private FieldMapper theFields;
	private QueryData theQuery;
	private BasicQueryData theBasicQuery;
	private JButton btnViewContig;
	private JButton btnHelp = null;
	private CachedTable contigTable;
	private JLabel lblSummary;
	private boolean isBasicQuery;
	private String [] theContigIDs = null; 
	private int nViewMode = -1;
    
    private static final long serialVersionUID = 1;
    
    private class ExportType extends JDialog {
		private static final long serialVersionUID = 6152973237315914324L;

		public static final int EXPORT_TABLE = 0;
		public static final int EXPORT_MEV = 1;
    	    public static final int EXPORT_UNITRANS = 2;
    	    public static final int EXPORT_R = 3;
    	    public static final int EXPORT_CANCEL = 4;
    	    public static final int EXPORT_ORF = 5;
    	    public static final int EXPORT_R2 = 6;
    	    public static final int EXPORT_GO = 7;
    	
    	    /***********************************************
    	     * the methods to output the files are in SortableTable in util.ui
    	     * Called above (search for Export button)
    	     */
        	public ExportType() {
        		setModal(true);
        		setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        		setTitle("Export.... ");
        		
        		btnTableTab = new JRadioButton("Table of columns (.csv)");
        		btnTableTab.addActionListener(new ActionListener() {
    				public void actionPerformed(ActionEvent arg0) {
    					nMode = EXPORT_TABLE;
    				}
    			});
        		btnUnitrans = new JRadioButton("Sequences from table (.fasta)");
            btnUnitrans.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    nMode = EXPORT_UNITRANS;
                }
            });
            btnORF = new JRadioButton("Translated ORFs from table (.fasta)");
            btnORF.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    nMode = EXPORT_ORF;
                }
                });
            
            btnTableMeV = new JRadioButton("Read counts from libraries in table (.mev)");
            btnTableMeV.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    nMode = EXPORT_MEV;
                }
            });		
        	
          	btnTableR = new JRadioButton("PCC of RPKM from libraries in table (.pcc, .sif)");
        		btnTableR.addActionListener(new ActionListener() {
    				public void actionPerformed(ActionEvent arg0) {
    					nMode = EXPORT_R;
    				}
    			});
        		btnTableR2 = new JRadioButton("PCC log2(RPKM) from libraries in table (.lg2.pcc, .lg2.sif)");
                btnTableR2.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent arg0) {
                        nMode = EXPORT_R2;
                    }
                });
                
            JLabel pccLabel = new JLabel("PCC cutoff: ");
    			
    			txtField  = new JTextField(6);
    			txtField.setMaximumSize(txtField.getPreferredSize());
    			txtField.setText("0.8");
    			
             	btnGOs = new JRadioButton("GOs from table (.csv)");
             	btnGOs.addActionListener(new ActionListener() {
    				public void actionPerformed(ActionEvent arg0) {
    					nMode = EXPORT_GO;
    				}
    			});
                 
             JLabel goLabel = new JLabel("GO Level: ");
    			
    			txtGO  = new JTextField(3);
    			txtGO.setMaximumSize(txtGO.getPreferredSize());
    			txtGO.setText("2");
    			       		
        		btnOK = new JButton("OK");
        		btnOK.addActionListener(new ActionListener() {
    				public void actionPerformed(ActionEvent e) {
    					setVisible(false);
    				}
    			});
        		btnCancel = new JButton("Cancel");
        		btnCancel.addActionListener(new ActionListener() {
    				public void actionPerformed(ActionEvent e) {
    					nMode = EXPORT_CANCEL;
    					setVisible(false);
    				}
    			});
        		
        		btnOK.setPreferredSize(btnCancel.getPreferredSize());
        		btnOK.setMaximumSize(btnCancel.getPreferredSize());
        		btnOK.setMinimumSize(btnCancel.getPreferredSize());
        		
        		ButtonGroup grp = new ButtonGroup();
        		grp.add(btnTableTab);
	            grp.add(btnUnitrans);
	            grp.add(btnORF); 
	            grp.add(btnTableMeV);
	           	grp.add(btnTableR);
	           	grp.add(btnTableR2);
	           	grp.add(btnGOs);
	   
	    		btnTableTab.setSelected(true);
	    		nMode = EXPORT_TABLE;
	    		
	            JPanel goPanel = new JPanel();
	            goPanel.setLayout(new BoxLayout(goPanel, BoxLayout.LINE_AXIS));
	            goPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
	            goPanel.add(Box.createHorizontalStrut(15));
	            goPanel.add(goLabel);
	            goPanel.add(txtGO);
	            goPanel.add(Box.createHorizontalGlue());
	
	            JPanel pccPanel = new JPanel();
	            pccPanel.setLayout(new BoxLayout(pccPanel, BoxLayout.LINE_AXIS));
	            pccPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
	            pccPanel.add(Box.createHorizontalStrut(15));
	            pccPanel.add(pccLabel);
	            pccPanel.add(txtField);
	            pccPanel.add(Box.createHorizontalGlue());
	
	    		JPanel selectPanel = new JPanel();
	    		selectPanel.setLayout(new BoxLayout(selectPanel, BoxLayout.PAGE_AXIS));
	    		selectPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
	    		selectPanel.add(btnTableTab);
	    		selectPanel.add(Box.createVerticalStrut(5));
	            selectPanel.add(btnUnitrans);
	            selectPanel.add(Box.createVerticalStrut(5));
	            selectPanel.add(btnORF);
	        	selectPanel.add(Box.createVerticalStrut(5));
	            selectPanel.add(btnTableMeV);
	            
	            selectPanel.add(Box.createVerticalStrut(10));
	          	selectPanel.add(btnTableR);		
	        	selectPanel.add(Box.createVerticalStrut(5));
	        	selectPanel.add(btnTableR2);  
	            selectPanel.add(Box.createVerticalStrut(5));
	            selectPanel.add(pccPanel);	   
	            if (getParentFrame().hasGOs())
	            {
	            	selectPanel.add(Box.createVerticalStrut(5));
	            	selectPanel.add(btnGOs);
	            	selectPanel.add(Box.createVerticalStrut(5));
	            	selectPanel.add(goPanel);
	            }
	 
	     
        		JPanel buttonPanel = new JPanel();
        		buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));
        		buttonPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
        		buttonPanel.add(btnOK);
        		buttonPanel.add(Box.createHorizontalStrut(20));
        		buttonPanel.add(btnCancel);
        		buttonPanel.setMaximumSize(buttonPanel.getPreferredSize());
  
           		JPanel mainPanel = new JPanel();
        		mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
        		mainPanel.setAlignmentX(Component.LEFT_ALIGNMENT);

        		mainPanel.add(selectPanel);
        		mainPanel.add(Box.createVerticalStrut(15));
        		mainPanel.add(buttonPanel);
        		
        		mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        		add(mainPanel);
        		
        		pack();
        		this.setResizable(false);
        		UIHelpers.centerScreen(this);
        	}
        	public String getPCCString() { return txtField.getText(); }
        	public String getGOLevel() { return txtGO.getText().trim(); }
        	public int getSelection() { return nMode; }
        	
        	JRadioButton btnTableTab = null;
        	JRadioButton btnTableMeV = null;
        	JRadioButton btnUnitrans = null;
        	JRadioButton btnTableR = null;
        	JRadioButton btnTableR2 = null;
        	JRadioButton btnORF = null;
        	JRadioButton btnGOs = null;
        	JTextField txtField = null;
        	JTextField txtGO = null;
        	
        	JButton btnOK = null;
        	JButton btnCancel = null;
        	
        	int nMode = -1;
    }
}